﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform.Windows;
using OpenTK;
/// <summary>
/// Clase que maneja el escenarrio principal donde se dibujan y controlan
/// todas las entidades
/// </summary>
/// JS: Juan Antonio Sanjuan jauanntonios@gmail.com 
public class Escenario
{

    #region "Construccion"

    public Escenario(GLControl objControl_)
    {
        this.PanelDibujo = objControl_;
        this.Coloreado = new Colores(0, 0, 0, 1);
        GL.BlendFunc(BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusSrcAlpha);
        GL.DepthFunc(DepthFunction.Lequal);
        GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
        GL.Enable(EnableCap.LineSmooth);
        GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
        GL.Enable(EnableCap.DepthTest);
        GL.Disable(EnableCap.Blend);
    }


    public void InitGL()
    {
        GL.ShadeModel(ShadingModel.Smooth);
        GL.ClearColor(0f, 0f, 0f, 0.5f);
        GL.ClearDepth(1d);
        GL.BlendFunc(BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusSrcAlpha);
        GL.DepthFunc(DepthFunction.Lequal);
        GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
        GL.Enable(EnableCap.LineSmooth);
        GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
        GL.Enable(EnableCap.DepthTest);
        GL.Disable(EnableCap.Blend);
    }

    public void iniciarCache()
    {
        //this.objCache= new CacheDXF(this, 2f, TIPO_ENTIDAD.Linea);
    }
    #endregion

    #region "Propiedades"

    GLControl objPanel;
    public GLControl PanelDibujo
    {
        get { return objPanel; }
        set { objPanel = value; }
    }

    private Colores _coloreado;
    public Colores Coloreado
    {
        get { return _coloreado; }
        set { _coloreado = value; }
    }

    private float _Aspecto;
    public float Aspecto
    {
        get { return _Aspecto; }
        set { _Aspecto = value; }
    }

    public Coordenada objLocalizacion;
    public Coordenada Localizacion
    {
        get {
            return this.objLocalizacion;
        }
        set {
            this.objLocalizacion.X = value.X ;
            this.objLocalizacion.Y = value.Y;
            if (value.Z > 0.0f)
            {
                this.objLocalizacion.Z = value.Z;
            }
        }
    }

    public void Zoom(float fltZoom)
    {
        this.objLocalizacion.Z += fltZoom;
    }



    public float Largo
    {
        get { return (float)this.PanelDibujo.Width; }
    }

    public float Alto
    {
        get { return (float)this.PanelDibujo.Height; }
    }
    #endregion

    #region "Metodos"
    /*public void centrar(ref Coordenada _objLocalizacion)
    {
        if (((objLocalizacion != null)))
        {
            this.Aspecto = this.Largo / this.Alto;
            /*if ((this.Aspecto > 1))
            {
                this.objLocalizacion.X = (_objLocalizacion.X) / this.Aspecto;
                this.objLocalizacion.Y = (_objLocalizacion.Y;
            }
            else
            {
                this.objLocalizacion.X = _objLocalizacion.X;
                this.objLocalizacion.Y = _objLocalizacion.Y * this.Aspecto;
            //}
        }
    }*/
    #endregion



    public unsafe void camara()
    {
        GL.ClearColor(this.Coloreado.Rojo, this.Coloreado.Verde, this.Coloreado.Azul, this.Coloreado.Alfa);
        GL.Viewport(this.PanelDibujo.ClientRectangle.Left, this.PanelDibujo.ClientRectangle.Top, this.PanelDibujo.ClientRectangle.Width, this.PanelDibujo.ClientRectangle.Height);
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        float aspecto = (float)this.PanelDibujo.Width / (float)this.PanelDibujo.Height;
        float mitadlargo = (float)objLocalizacion.Z * aspecto;
        GL.Ortho(objLocalizacion.X - mitadlargo, objLocalizacion.X + mitadlargo, objLocalizacion.Y - objLocalizacion.Z, objLocalizacion.Y + objLocalizacion.Z, 1f, -1f);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
    }

    public unsafe Coordenada coordenadasXY(float xVentana, float yVentana)
    {
        /*Coordenada objRetorno = new Coordenada(0, 0);
        //Calcula el inverso de yVentana para Queue hacia abajo disminuya yVentana hacia arriba aumente
        yVentana = PanelDibujo.Height - yVentana;
        objRetorno.X = (2 * this.objLocalizacion.Z * xVentana) / PanelDibujo.Width;
        objRetorno.X = (objRetorno.X + objLocalizacion.X) - this.objLocalizacion.Z;
        objRetorno.Y = (2 * this.objLocalizacion.Z * yVentana) / PanelDibujo.Height;
        objRetorno.Y = (objRetorno.Y + objLocalizacion.Y) - this.objLocalizacion.Z;
        return objRetorno;*/
        int[] viewport = new int[5];
        double[] modelview = new double[17];
        double[] projection = new double[17];
        double winX = 0;
        double winY = 0;
        double winZ = 0;
        double[] posX = new double[1];
        double[] posY = new double[1];
        double[] posZ = new double[1];
        GL.GetDouble(GetPName.ModelviewMatrix, modelview);
        GL.GetDouble(GetPName.ProjectionMatrix, projection);
        GL.GetInteger(GetPName.Viewport, viewport);
        winX = xVentana;
        winY = viewport[3] - yVentana;
        OpenTK.Graphics.Glu.UnProject(winX, winY, winZ, modelview, projection, viewport, posX, posY, posZ);
        return new Coordenada((float)posX[0], (float)posY[0]);
    }

    public Capa objCapaPrueba;
    //private CacheDXF objCache;

    public unsafe void pintar()
    {
        //aqui esta la camara
        camara();
        objPanel.SwapBuffers();
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        foreach (IEntidad objEntidad in objEntidades.Values)
        {
            objEntidad._pintar();
        }
        /*if (objCache != null)
        {
            objCache._pintar();
        }*/
        GL.Flush();
    }

    public void refrescar()
    {
        Coordenada objCoordenadaAntigua = new Coordenada(this.objLocalizacion.X, this.objLocalizacion.Y, this.objLocalizacion.Z);
        this.Localizacion = new Coordenada(-100, -100, 1);
        this.pintar();
        this.objLocalizacion.X  = objCoordenadaAntigua.X;
        this.objLocalizacion.Y = objCoordenadaAntigua.Y;
        this.objLocalizacion.Z = objCoordenadaAntigua.Z;
        this.pintar();
    }

    public System.Collections.Hashtable objEntidades = new System.Collections.Hashtable(8388617, 0.75F);
    public void adicionar(IEntidad objEntidad)
    {
        objEntidades.Add(objEntidad.ID, objEntidad);
    }

    public void eliminar(object objEntidad)
    {
        objEntidades.Remove(objEntidad);
    }

    public unsafe DataSet buscarInfo(int x, int y)
    {
        DataSet objRetorno = new DataSet();
        CapaSQL objCapa = null;
        Coordenada objCoordenada = coordenadasXY(x, y);
        DataTable objTabla = null;
        foreach (IEntidad objEntidad in objEntidades.Values)
        {
            if (objEntidad.Tabla != "")
            {
                try
                {
                    if (objEntidad.GetType().Name.Equals("CapaSQL"))
                    {
                        objCapa = (CapaSQL)objEntidad;
                        objTabla = objCapa.buscarDatos(objCoordenada);
                        objTabla.TableName = objEntidad.ID;
                        objRetorno.Tables.Add(objTabla);
                    }
                }
                catch (Exception)
                {
                }
            }
        }
        return objRetorno;
    }
}
